<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  
  <script>
    /**
     * 帖子出处
     * https://fe.ecool.fun/articles/technology/742
     */
    function reportTiming(url, duration, isError = false) {
      console.log(`[请求监控] ${url} - ${duration}ms ${isError ? '(失败)' : ''}`);
      // TODO: 上报给服务端或监控平台
    }
    //fetch
    const originalFetch = window.fetch;

    window.fetch = asyncfunction(...args) {
      const start = Date.now();
      try {
        const response = await originalFetch.apply(this, args);
        const end = Date.now();

        reportTiming(args[0], end - start); // 上报地址 & 耗时
        return response;
      } catch (err) {
        const end = Date.now();
        reportTiming(args[0], end - start, true);
        throw err;
      }
    };

    //XHR 
    const originalXHR = window.XMLHttpRequest;

    function wrapXHR() {
      const oldOpen = originalXHR.prototype.open;
      const oldSend = originalXHR.prototype.send;

      originalXHR.prototype.open = function (method, url, async) {
        this._url = url;
        oldOpen.apply(this, arguments);
      };

      originalXHR.prototype.send = function (...args) {
        const start = Date.now();

        this.addEventListener('loadend', () => {
          const duration = Date.now() - start;
          reportTiming(this._url, duration, this.status >= 400);
        });

        oldSend.apply(this, args);
      };
    }

    wrapXHR();

    //推荐的上报方式：navigator.sendBeacon
    function reportTiming2(url, duration, isError = false) {
      const data = {
        url,
        duration,
        status: isError ? 'error' : 'ok',
        timestamp: Date.now(),
      };

      const blob = new Blob([JSON.stringify(data)], { type: 'application/json' });
      navigator.sendBeacon('/monitor/collect', blob);
    }
  </script>
</body>

</html>